package ru.niir.goodfil.db;

import org.apache.commons.lang.StringUtils;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

import static ru.niir.goodfil.utils.Utils._assertNotBlank;
import static ru.niir.goodfil.utils.Utils.s;

/**
 * Товар (в каталоге товаров)
 */
@Entity
@Table(name = "`Goods`")
public class Good implements Unique ,Serializable {

    /**
     * Идентификатор товара
     */
    @Id
    @GeneratedValue
    @Column(name = "`Id`", nullable = false, length = 10)
    private long id = -1;

    /**
     * Код товара.
     * Должен быть уникален.
     */
    @Column(name = "`Code`", nullable = false)
    private String code = "";

    /**
     * Код товара в 1С.
     * Должэен быть уникален, если заполнен
     */
    @Column(name = "`1CCode`", nullable = true)
    private String c1code;

    /**
     * Флаг фиктивного удаления товара
     */
    @Column(name = "`IsDeleted`")
    private boolean deleted = false;

    /**
     * Наименование товара
     */
    @Column(name = "`Name`", nullable = false)
    private String name = "";

    /**
     * Минимальная цена
     */
    @Column(name = "`MinPrice`", nullable = false)
    private float minPrice = 0;

    /**
     * Вес товара
     */
    @Column(name = "`Weight`", nullable = false)
    private float weight = 0;

    /**
     * Объекм товара
     */
    @Column(name = "`Volume`", nullable = false)
    private float volume = 0;

    /**
     * M&H кроссы
     */
    @Column(name = "`mh`", nullable = false)
    private String mh = "";

    /**
     * Оригинальные номера
     */
    @Column(name = "`oe`", nullable = false)
    private String oe = "";

    /**
     * Применимость
     */
    @Column(name = "`pr`", nullable = false)
    private String pr = "";

    /**
     * Идентификатор группы товаров
     */
    @Column(name = "`IdGoodType`", nullable = false)
    private long goodTypeId = -1;

    /**
     * Количество товара на слкладе
     */
    @Column(name = "`Count`")
    private int count = 0;

    /**
     * Количество товара на слкладе
     */
    @Column(name = "`ReservedCount`")
    private int reservedCount = 0;

    /**
     * Количество штук в упаковке
     */
    @Column(name = "`PackageCount`")
    private String packageCount = "1";

    /**
     * Идентификатор брэнда, к которому относится товар
     */
    @Column(name = "`IdBrand`")
    private Long brandId;

    /**
     * Количество, начиная с которого налие считается малым
     */
    @Column(name = "DangerousRest")
    private int dangerousRest;

    /**
     * Количество на складе
     */
    @Column(name = "StorageCount")
    private int storageCount;

    /**
     * Кооментарий
     */
    @Column(name="Comment")
    private String coment;

/*    @Column(name = "ReservedCountIs")
    private int reservedCountIs;*/
    /**
     * Группа товаров
     */
    @Transient
    private GoodType goodType;

    /**
     * Флаг того, что данный товар отмечен для некоторой операции
     */
    @Transient
    private boolean isSelected;

    /**
     * Для ситуаций, когда требуется хранить все цены товара
     * Ключ - идентификатор клиентской группы
     * Значение - цена
     */
    @Transient
    private final Map<Long /*clientGroupId*/, Float /*price*/> pricesMap = new HashMap<Long, Float>();

    @Transient
    private BigInteger salesForMonth;

    @Transient
    private BigInteger salesForThreeMonths;

    @Transient
    private BigInteger salesForSixMonths;
    
    @Transient
    private int goodAbsenceCount = 0;

    @Transient
    private int ordersCount = 0;

/*    @Transient
    private int fullReservedCount;

    public int getFullReservedCount() {
        return getReservedCount() + getReservedCountIs();
    }

    public int getReservedCountIs() {
        return reservedCountIs;
    }

    public void setReservedCountIs(int reservedCountIs) {
        this.reservedCountIs = reservedCountIs;
    }*/

    public int getOrdersCount() {
        return ordersCount;
    }

    public void setOrdersCount(int ordersCount) {
        this.ordersCount = ordersCount;
    }

    public int getStorageCount() {
        return storageCount;
    }

    public void setStorageCount(int storageCount) {
        this.storageCount = storageCount;
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    /**
     * Получить код товара
     */
    public String getCode() {
        return code;
    }

    /**
     * Установить код товара
     */
    public void setCode(String code) {
        this.code = s(code);
    }

    /**
     * Получить наименование товара
     */
    public String getName() {
        return name;
    }

    /**
     * Получить полное наименование товара, строку вида: <код> <наменование>
     */
    public String getFullName() {
        return code + " " + name;
    }

    /**
     * Установить наименование товара
     */
    public void setName(String name) {
        this.name = s(name);
    }

    /**
     * Получить вес товара
     */
    public float getWeight() {
        return weight;
    }

    /**
     * Установить вес товара
     */
    public void setWeight(float weight) {
        this.weight = weight;
    }

    /**
     * Получить объекм товара
     */
    public float getVolume() {
        return volume;
    }

    /**
     * Установить объем товара
     */
    public void setVolume(float volume) {
        this.volume = volume;
    }

    /**
     * Получить ссылку на группу товаров для данного товара
     */
    public GoodType getGoodType() {
        return goodType;
    }

    /**
     * Установить ссылку на группу товаров для данного товара
     */
    public void setGoodType(GoodType goodType) {
        assert goodType != null;
        assert goodType.getId() == goodTypeId;

        this.goodType = goodType;
    }

    /**
     * Получить идентификатор группы товаров, к которой относится данный товар
     */
    public long getGoodTypeId() {
        return goodTypeId;
    }

    /**
     * Установить идентификатор группы товаров, к которой относится данный товар
     */
    public void setGoodTypeId(long goodTypeId) {
        this.goodTypeId = goodTypeId;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getReservedCount() {
        return reservedCount;
    }

    public void setReservedCount(int reservedCount) {
        this.reservedCount = reservedCount;
    }

    /**
     * Количество штук в упаковке
     */
    public String getPackageCount() {
        return packageCount;
    }

    /**
     * Количество штук в упаковке
     */
    public void setPackageCount(String packageCount) {
        this.packageCount = packageCount;
    }

    //
    //  Три неизвестных колонки из прайса  -------------------
    //

    public String getMh() {
        return mh;
    }

    public void setMh(String mh) {
        this.mh = s(mh);
    }

    public String getOe() {
        return oe;
    }

    public void setOe(String oe) {
        this.oe = s(oe);
    }

    public String getPr() {
        return pr;
    }

    /**
     * Возвращает применимость товара в которкой форме - первые 20 символов
     *
     * @return применимость товара в которкой форме - первые 20 символов
     */
    public String getPrShort() {
        pr = s(pr);

        if (pr.length() < 20) return pr;
        else return pr.substring(0, 20) + " [...]";
    }

    public String getOeShort() {
        oe = s(oe);

        if (oe.length() < 20) return oe;
        else return oe.substring(0, 20) + " [...]";
    }

    public void setPr(String pr) {
        this.pr = s(pr);
    }

    public float getMinPrice() {
        return minPrice;
    }

    public void setMinPrice(float minPrice) {
        this.minPrice = minPrice;
    }

    public String getC1code() {
        return c1code;
    }

    public void setC1code(String c1code) {
        this.c1code = c1code.trim();
    }

    public boolean isDeleted() {
        return deleted;
    }

    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }

    public boolean isSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }

    public int getDangerousRest() {
        return dangerousRest;
    }

    public void setDangerousRest(int dangerousRest) {
        this.dangerousRest = dangerousRest;
    }

    public String getComent() {
        return coment;
    }

    public void setComent(String coment) {
        this.coment = coment;
    }

    public BigInteger getSalesForMonth() {
        return salesForMonth;
    }

    public void setSalesForMonth(BigInteger salesForMonth) {
        this.salesForMonth = salesForMonth;
    }

    public BigInteger getSalesForThreeMonths() {
        return salesForThreeMonths;
    }

    public void setSalesForThreeMonths(BigInteger salesForThreeMonths) {
        this.salesForThreeMonths = salesForThreeMonths;
    }

    public BigInteger getSalesForSixMonths() {
        return salesForSixMonths;
    }

    public void setSalesForSixMonths(BigInteger salesForSixMonths) {
        this.salesForSixMonths = salesForSixMonths;
    }

    /**
     * Для ситуаций, когда требуется хранить все цены товара
     * Ключ - идентификатор клиентской группы
     * Значение - цена
     */
    public Map<Long /*clientGroupId*/, Float /*price*/> getPricesMap() {
        return pricesMap;
    }

    public void setPricesMapString(String s) {
        _assertNotBlank(s);

        pricesMap.clear();
        String[] arr = s.split(" ");
        for (String ar : arr) {
            String[] brr = ar.split("=");
            long clientGroupId = new Long(brr[0]);
            float price = new Float(brr[1]);
            pricesMap.put(clientGroupId, price);
        }
    }

    public Long getBrandId() {
        return brandId;
    }

    public void setBrandId(Long brandId) {
        this.brandId = brandId;
    }

    public int getGoodAbsenceCount() {
        return goodAbsenceCount;
    }

    public void setGoodAbsenceCount(int goodAbsenceCount) {
        this.goodAbsenceCount = goodAbsenceCount;
    }

    public int getGoodCountDifference(){
        return Math.abs(getCount() - getStorageCount());
    }

    //
    //  ------------------------------------------------------
    //

    /**
     * Возвращает true, если у товара отсутствует код соответствия с 1С
     *
     * @return true, если у товара отсутствует код соответствия с 1С
     */
    public boolean getC1CodeIsMissing() {
        return StringUtils.isBlank(c1code);
    }

    @Override
    public String toString() {
        return "Good{" +
                "id=" + id +
                ", code='" + code + '\'' +
                ", c1code='" + c1code + '\'' +
                ", deleted=" + deleted +
                ", name='" + name + '\'' +
                ", minPrice=" + minPrice +
                ", weight=" + weight +
                ", volume=" + volume +
                ", mh='" + mh + '\'' +
                ", oe='" + oe + '\'' +
                ", pr='" + pr + '\'' +
                ", goodTypeId=" + goodTypeId +
                ", count=" + count +
                ", packageCount=" + packageCount +
                ", goodType=" + goodType +
                ", isSelected=" + isSelected +
                ", dangerousRest=" + dangerousRest +
                ", coment=" + coment +
                '}';
    }

    public Good duplicate() {
        Good good = new Good();

        good.id = this.id;
        good.code = this.code;
        good.c1code = this.c1code;
        good.name = this.name;
        good.minPrice = this.minPrice;
        good.weight = this.weight;
        good.volume = this.volume;
        good.mh = this.mh;
        good.oe = this.oe;
        good.pr = this.pr;
        good.goodTypeId = this.goodTypeId;
        good.count = this.count;
        good.packageCount = this.packageCount;
        good.goodType = this.goodType;
        good.isSelected = this.isSelected;
        good.dangerousRest = this.dangerousRest;
        good.coment = this.coment;

        return good;
    }
}
